Android 開発者向けの Flutter
このドキュメントは、Android のアプリケーションを適用しようとしている Android 開発者を対象としています。 Flutter を使用してモバイル アプリを構築するための既存の Android 知識。 Android フレームワークの基礎を理解していれば、 このドキュメントを Flutter 開発へのジャンプスタートとして使用できます。
Android を使って構築する場合、あなたの Android の知識とスキルセットは非常に価値があります。 Flutter は、多くの機能でモバイル オペレーティング システムに依存しているため、 機能と構成。 Flutter はモバイル用の UI を構築する新しい方法です。 ただし、非 UI 用に Android (および iOS) と通信するためのプラグイン システムがあります。 タスク。 Android のエキスパートであれば、すべてを学び直す必要はありません flutterを使用します。
このドキュメントは、飛び回ったり、クックブックとして使用したりできます。 自分のニーズに最も関連する質問を見つけます。
ビュー
Flutter の View に相当するものは何ですか?
Android では、View
に表示されるすべての基礎です。
画面。ボタン、ツールバー、入力など、すべてがビューです。
Flutter では、おおよそ次のものに相当します。View
ですWidget
。
ウィジェットは Android ビューに正確にマッピングされませんが、
Flutter の仕組みを理解していれば、次のように考えることができます。
「UI を宣言して構築する方法」。
ただし、これらにはいくつかの違いがあります。View
。まず、ウィジェットには
異なるライフスパン: それらは不変であり、必要になるまでのみ存在します。
かわった。ウィジェットまたはその状態が変化するたびに、Flutter のフレームワークは
ウィジェット インスタンスの新しいツリー。比較すると、Android ビューは 1 回描画されます。
そしてそれまで再描画しませんinvalidate
と呼ばれます。
Flutter のウィジェットは、その不変性のおかげで軽量です。 それらはビューそのものではなく、直接何かを描画しているわけではないため、 むしろ、「膨張」する UI とそのセマンティクスの説明です。 ボンネットの下にある実際のビュー オブジェクトに反映されます。
flutterには以下が含まれます材料成分図書館。 これらは、マテリアル デザインのガイドライン。マテリアルデザインというのは、 柔軟な設計システムすべてのプラットフォーム向けに最適化、 iOSも含めて。
しかし、Flutter は、あらゆる設計言語を実装できる柔軟性と表現力を備えています。 たとえば、iOS では、クパチーノのウィジェット次のようなインターフェイスを生成しますAppleのiOSデザイン言語。
ウィジェットを更新するにはどうすればよいですか?
Android では、ビューを直接変更することでビューを更新します。しかし、
flutterでは、Widget
は不変であり、直接更新されません。
代わりに、ウィジェットの状態を操作する必要があります。
ここでのコンセプトは、Stateful
とStateless
ウィジェットはから来ています。
あStatelessWidget
それはまさにそのように聞こえます—
状態情報を持たないウィジェット。
StatelessWidgets
ユーザーインターフェイスの一部である場合に便利です
あなたが説明していることは、構成以外のものには依存しません
オブジェクト内の情報。
たとえば、Android では、これはImageView
あなたのロゴと一緒に。実行中にロゴが変わることはありませんが、
だから、を使用してくださいStatelessWidget
flutterで。
受信したデータに基づいて動的にUIを変更したい場合
HTTP 呼び出しまたはユーザー インタラクションを行った後は、作業する必要があります
とStatefulWidget
Flutter フレームワークにウィジェットのState
が更新されているため、そのウィジェットを更新できるようになります。
ここで注意すべき重要なことは、ステートレスとステートフルの両方が核となるということです。
ウィジェットも同じように動作します。すべてのフレームを再構築しますが、違いは次のとおりです。StatefulWidget
がありますState
フレーム全体の状態データを保存するオブジェクト
そしてそれを復元します。
迷った場合は、次のルールを常に覚えておいてください: ウィジェットが変更された場合 (ユーザーの操作などのため) ステートフルです。 ただし、ウィジェットが変更に反応する場合、それを含む親ウィジェットは、 それ自体が変化に反応しない場合は、ステートレスのままです。
次の例は、StatelessWidget
。共通のStatelessWidget
それはText
ウィジェット。の実装を見てみると、
のText
ウィジェットはサブクラス化されていることがわかりますStatelessWidget
。
Text(
'I like Flutter!',
style: TextStyle(fontWeight: FontWeight.bold),
);
ご覧のとおり、Text
ウィジェットには状態情報が関連付けられていません。
コンストラクターで渡されたものだけをレンダリングします。
しかし、「I Like Flutter」を動的に変更したい場合はどうすればよいでしょうか。
をクリックしたときの例FloatingActionButton
?
これを実現するには、Text
のウィジェットStatefulWidget
と
ユーザーがボタンをクリックすると更新されます。
例えば:
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
// Default placeholder text.
String textToShow = 'I Like Flutter';
void _updateText() {
setState(() {
// Update the text.
textToShow = 'Flutter is Awesome!';
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: Center(child: Text(textToShow)),
floatingActionButton: FloatingActionButton(
onPressed: _updateText,
tooltip: 'Update Text',
child: const Icon(Icons.update),
),
);
}
}
ウィジェットをレイアウトするにはどうすればよいですか? XML レイアウト ファイルはどこにありますか?
Android ではレイアウトを XML で記述しますが、Flutter ではレイアウトを記述します。 ウィジェットツリー付き。
次の例は、パディング付きの単純なウィジェットを表示する方法を示しています。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.only(left: 20, right: 30),
),
onPressed: () {},
child: const Text('Hello'),
),
),
);
}
Flutter が提供するレイアウトの一部は、ウィジェットカタログ。
レイアウトにコンポーネントを追加または削除するにはどうすればよいですか?
Android では、次のように呼び出します。addChild()
またremoveChild()
親上で子ビューを動的に追加または削除します。
Flutter では、ウィジェットは不変であるため、
直接的に相当するものはありませんaddChild()
。その代わり、
ウィジェットを返す関数を親に渡すことができます。
そしてその子の作成をブールフラグで制御します。
たとえば、2 つのモードを切り替える方法は次のとおりです。
ウィジェットをクリックすると、FloatingActionButton
:
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
// Default value for toggle.
bool toggle = true;
void _toggle() {
setState(() {
toggle = !toggle;
});
}
Widget _getToggleChild() {
if (toggle) {
return const Text('Toggle One');
} else {
return ElevatedButton(
onPressed: () {},
child: const Text('Toggle Two'),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: Center(
child: _getToggleChild(),
),
floatingActionButton: FloatingActionButton(
onPressed: _toggle,
tooltip: 'Update Text',
child: const Icon(Icons.update),
),
);
}
}
ウィジェットをアニメーション化するにはどうすればよいですか?
Android では、XML を使用してアニメーションを作成するか、animate()
ビューのメソッド。 Flutter では、アニメーションを使用してウィジェットをアニメーション化します。
アニメーション化されたウィジェット内にウィジェットをラップすることでライブラリを作成します。
Flutter では、AnimationController
それはAnimation<double>
アニメーションを一時停止、シーク、停止、反転できます。それには、Ticker
これは、vsync が発生したときに信号を送り、その間の線形補間を生成します。
実行中の各フレームの 0 と 1。次に、1 つ以上を作成しますAnimation
s をコントローラーに取り付けます。
たとえば、次のように使用できます。CurvedAnimation
アニメーションを実装するには
補間された曲線に沿って。そういう意味ではコントローラーは
はアニメーションの進行状況の「マスター」ソースであり、CurvedAnimation
コントローラのデフォルトの直線運動を置き換える曲線を計算します。
ウィジェットと同様に、Flutter のアニメーションは合成で動作します。
ウィジェット ツリーを構築するときに、Animation
アニメーションに
ウィジェットの不透明度などのプロパティFadeTransition
、と伝えます。
コントローラーを押してアニメーションを開始します。
次の例は、FadeTransition
それは色褪せます
を押すとウィジェットがロゴに組み込まれますFloatingActionButton
:
import 'package:flutter/material.dart';
void main() {
runApp(const FadeAppTest());
}
class FadeAppTest extends StatelessWidget {
const FadeAppTest({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fade Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyFadeTest(title: 'Fade Demo'),
);
}
}
class MyFadeTest extends StatefulWidget {
const MyFadeTest({super.key, required this.title});
final String title;
@override
State<MyFadeTest> createState() => _MyFadeTest();
}
class _MyFadeTest extends State<MyFadeTest> with TickerProviderStateMixin {
late AnimationController controller;
late CurvedAnimation curve;
@override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 2000),
vsync: this,
);
curve = CurvedAnimation(
parent: controller,
curve: Curves.easeIn,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: FadeTransition(
opacity: curve,
child: const FlutterLogo(
size: 100,
),
),
),
floatingActionButton: FloatingActionButton(
tooltip: 'Fade',
onPressed: () {
controller.forward();
},
child: const Icon(Icons.brush),
),
);
}
}
詳細については、を参照してください。アニメーションとモーションのウィジェット、 のアニメーションのチュートリアル、 そしてそのアニメーションの概要。
Canvas を使用して描画/ペイントするにはどうすればよいですか?
Android では、Canvas
とDrawable
画像や図形を画面に描画します。
Flutterにも同様のものがありますCanvas
APIもそうですが、
同じ低レベルのレンダリング エンジンである Skia に基づいているためです。
その結果、Flutter でキャンバスにペイントする
Android 開発者にとっては非常に馴染みのあるタスクです。
Flutter には、キャンバスへの描画に役立つ 2 つのクラスがあります。CustomPaint
とCustomPainter
、
後者は、キャンバスに描画するアルゴリズムを実装します。
Flutter で署名ペインタを実装する方法を学ぶには、 コリンの答えを参照してくださいカスタムペイント。
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: DemoApp()));
class DemoApp extends StatelessWidget {
const DemoApp({super.key});
@override
Widget build(BuildContext context) => const Scaffold(body: Signature());
}
class Signature extends StatefulWidget {
const Signature({super.key});
@override
SignatureState createState() => SignatureState();
}
class SignatureState extends State<Signature> {
List<Offset?> _points = <Offset>[];
@override
Widget build(BuildContext context) {
return GestureDetector(
onPanUpdate: (details) {
setState(() {
RenderBox? referenceBox = context.findRenderObject() as RenderBox;
Offset localPosition =
referenceBox.globalToLocal(details.globalPosition);
_points = List.from(_points)..add(localPosition);
});
},
onPanEnd: (details) => _points.add(null),
child: CustomPaint(
painter: SignaturePainter(_points),
size: Size.infinite,
),
);
}
}
class SignaturePainter extends CustomPainter {
SignaturePainter(this.points);
final List<Offset?> points;
@override
void paint(Canvas canvas, Size size) {
var paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null) {
canvas.drawLine(points[i]!, points[i + 1]!, paint);
}
}
}
@override
bool shouldRepaint(SignaturePainter oldDelegate) =>
oldDelegate.points != points;
}
カスタム ウィジェットを作成するにはどうすればよいですか?
Android では通常、サブクラス化します。View
、または既存のビューを使用します。
目的の動作を実現するメソッドをオーバーライドして実装します。
Flutter では、次のようにカスタム ウィジェットを構築します。作曲する(ウィジェットを拡張する代わりに) より小さなウィジェットを作成します。
カスタムの実装に似ていますViewGroup
Android では、すべての構成要素がすでに存在しています。
ただし、別の動作を提供します。たとえば、
カスタム レイアウト ロジック。
たとえば、どうやって構築しますかCustomButton
それはラベルを取り込みます
コンストラクターは?を構成する CustomButton を作成します。ElevatedButton
と
ラベルを拡張するのではなく、ElevatedButton
:
class CustomButton extends StatelessWidget {
final String label;
const CustomButton(this.label, {super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {},
child: Text(label),
);
}
}
次に、使用しますCustomButton
他の Flutter ウィジェットを使用するのと同じように、
@override
Widget build(BuildContext context) {
return const Center(
child: CustomButton('Hello'),
);
}
インテント
Flutter のインテントに相当するものは何ですか?
Android には、主に 2 つの使用例があります。Intent
s: 間を移動します
アクティビティ、およびコンポーネントとの通信。一方、 flutterは、
インテントの概念はありませんが、インテントを開始することはできます。
ネイティブ統合を通じて (使用プラグイン)。
Flutter にはアクティビティやフラグメントに直接相当するものはありません。
むしろ、Flutter では、Navigator
とRoute
すべて同じ内にありますActivity
。
あRoute
アプリの「画面」または「ページ」の抽象化です。Navigator
ルートを管理するウィジェットです。ルートはおおよそ次のようにマッピングされます。Activity
, しかし、同じ意味ではありません。ナビゲーターがプッシュできる
およびポップルートを使用して画面から画面に移動します。ナビゲーターはスタックのように機能します
どれでできるかpush()
移動先または出発地となる新しいルート
あなたができることpop()
「戻りたい」ときのルート。
Android では、アプリ内でアクティビティを宣言します。AndroidManifest.xml
。
Flutter では、ページ間を移動するためのオプションがいくつかあります。
- を指定してください
Map
路線名のこと。 (使用してMaterialApp
) - ルートに直接移動します。 (使用して
WidgetsApp
)
次の例ではマップを構築します。
void main() {
runApp(MaterialApp(
home: const MyAppHome(), // Becomes the route named '/'.
routes: <String, WidgetBuilder>{
'/a': (context) => const MyPage(title: 'page A'),
'/b': (context) => const MyPage(title: 'page B'),
'/c': (context) => const MyPage(title: 'page C'),
},
));
}
ルートに移動するにはpush
その名前をNavigator
。
Navigator.of(context).pushNamed('/b');
もう 1 つの一般的なユースケースは、Intent
s は、次のような外部コンポーネントを呼び出すことです。
カメラまたはファイルピッカーとして。このためには、ネイティブ プラットフォームを作成する必要があります。
統合 (または既存のプラグイン)。
ネイティブ プラットフォーム統合を構築する方法を学ぶには、 見るパッケージとプラグインの開発。
Flutter で外部アプリケーションから受信したインテントをどのように処理すればよいですか?
Flutter は、Android からの受信インテントを直接処理することができます。 Android レイヤーと共有されたデータをリクエストします。
次の例では、テキスト共有インテント フィルターをネイティブに登録します。 Flutter コードを実行するアクティビティ。これにより、他のアプリがテキストを共有できるようになります。 Flutter アプリ。
基本的なフローは、最初に共有テキスト データを
Android ネイティブ側 (私たちのActivity
)、Flutter がリクエストするまで待ちます
データを使用して提供するには、MethodChannel
。
まず、すべてのインテントのインテント フィルターをAndroidManifest.xml
:
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- ... -->
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
それからMainActivity
、インテントを処理し、含まれていたテキストを抽出します。
意図から共有し、それを保持します。 Flutter が処理できる状態になったら、
プラットフォーム チャネルを使用してデータをリクエストし、送信されます
ネイティブ側の向かい側:
package com.example.shared;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
private String sharedText;
private static final String CHANNEL = "app.channel.shared.data";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent); // Handle text being sent
}
}
}
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
if (call.method.contentEquals("getSharedText")) {
result.success(sharedText);
sharedText = null;
}
}
);
}
void handleSendText(Intent intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
}
}
最後にFlutter側にデータをリクエストします。 ウィジェットがレンダリングされるとき:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample Shared App Handler',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
static const platform = MethodChannel('app.channel.shared.data');
String dataShared = 'No data';
@override
void initState() {
super.initState();
getSharedText();
}
@override
Widget build(BuildContext context) {
return Scaffold(body: Center(child: Text(dataShared)));
}
Future<void> getSharedText() async {
var sharedData = await platform.invokeMethod('getSharedText');
if (sharedData != null) {
setState(() {
dataShared = sharedData;
});
}
}
}
startActivityForResult() に相当するものは何ですか?
のNavigator
クラスは Flutter でルーティングを処理し、取得するために使用されます。
スタックにプッシュしたルートから返された結果。
これを行うのは、await
上にいるFuture
によって返されましたpush()
。
たとえば、ユーザーが選択できる位置ルートを開始するには、 その位置を確認するには、次のことができます。
Object? coordinates = await Navigator.of(context).pushNamed('/location');
そして、ユーザーが自分の場所を選択すると、場所のルート内で
あなたはできるpop
結果を含むスタック:
Navigator.of(context).pop({'lat': 43.821757, 'long': -79.226392});
非同期UI
Flutter の runOnUiThread() に相当するものは何ですか?
Dart にはシングルスレッド実行モデルがあり、Isolate
s
(別のスレッドで Dart コードを実行する方法)、イベント ループ、および
非同期プログラミング。あなたがスポーンしない限り、Isolate
、ダーツコード
メイン UI スレッドで実行され、イベント ループによって駆動されます。 flutterのイベント
ループはAndroidのメインに相当しますLooper
—つまり、Looper
それか
メインスレッドに接続されています。
Dart のシングルスレッド モデルは、すべてを 1 つのスレッドとして実行する必要があるという意味ではありません。
UI のフリーズを引き起こす操作をブロックします。 Android とは異なり、
Flutter では、メインスレッドを常にフリーにしておく必要があります。
Dart 言語が提供する非同期機能を使用します。async
/await
、非同期作業を実行します。あなたもよく知っているかもしれません
のasync
/await
C#、JavaScript でパラダイムを使用したことがある場合、または
Kotlin のコルーチンを使用しました。
たとえば、UI をハングさせることなくネットワーク コードを実行できます。
使用してasync
/await
そして、Dart に面倒な作業を任せます。
Future<void> loadData() async {
var dataURL = Uri.parse('https://jsonplaceholder.typicode.com/posts');
http.Response response = await http.get(dataURL);
setState(() {
widgets = jsonDecode(response.body);
});
}
一度await
ネットワーク呼び出しが完了しました。呼び出して UI を更新しますsetState()
、
これにより、ウィジェットのサブツリーの再構築がトリガーされ、データが更新されます。
次の例では、データを非同期的にロードし、それをListView
:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List widgets = [];
@override
void initState() {
super.initState();
loadData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: ListView.builder(
itemCount: widgets.length,
itemBuilder: (context, position) {
return getRow(position);
},
),
);
}
Widget getRow(int i) {
return Padding(
padding: const EdgeInsets.all(10),
child: Text("Row ${widgets[i]["title"]}"),
);
}
Future<void> loadData() async {
var dataURL = Uri.parse('https://jsonplaceholder.typicode.com/posts');
http.Response response = await http.get(dataURL);
setState(() {
widgets = jsonDecode(response.body);
});
}
}
での作業の詳細については、次のセクションを参照してください。 背景、および Flutter と Android の違いについて説明します。
作業をバックグラウンド スレッドに移動するにはどうすればよいでしょうか?
Android では、ネットワーク リソースにアクセスする場合、通常は次のようにします。
メインスレッドをブロックしないように、バックグラウンドスレッドに移動して作業を実行します。
そしてANRを避けてください。たとえば、次のようなものを使用している可能性があります。AsyncTask
、LiveData
、
のIntentService
、JobScheduler
ジョブ、または RxJava パイプライン
バックグラウンドスレッドで動作するスケジューラ。
Flutter はシングルスレッドでイベント ループ (Node.js など) を実行するため、
スレッド管理やバックグラウンド スレッドの生成について心配する必要はありません。もしも
ディスク アクセスやネットワーク呼び出しなど、I/O バウンドの作業を行っている場合
安全に使用できますasync
/await
これで準備は完了です。一方、もし、
一方、CPU をビジー状態にし続ける計算集約的な作業を行う必要があるため、
それをに移動したいのですが、Isolate
イベントループのブロックを避けるため、次のように
あなたは保管するでしょうどれでもAndroid のメインスレッドから外れた一種の作業です。
I/O バウンドの作業の場合は、関数を次のように宣言します。async
関数、
とawait
関数内の長時間実行タスクの場合:
Future<void> loadData() async {
var dataURL = Uri.parse('https://jsonplaceholder.typicode.com/posts');
http.Response response = await http.get(dataURL);
setState(() {
widgets = jsonDecode(response.body);
});
}
これは、通常、ネットワーク呼び出しまたはデータベース呼び出しを行う方法です。 I/O 操作。
Android で拡張すると、AsyncTask
通常、3 つのメソッドをオーバーライドします。onPreExecute()
、doInBackground()
とonPostExecute()
。ありません
Flutterでも同等です。await
長時間実行される関数について、そして
Dart のイベント ループが残りを処理します。
ただし、大量のデータを処理する場合や、
UI がハングします。 Flutterでは、使用しますIsolate
を活用する
複数の CPU コアを使用して、長時間実行または計算負荷の高いタスクを実行します。
アイソレートはメモリを共有しない別個の実行スレッドです。
メイン実行メモリヒープを使用します。これは、から変数にアクセスできないことを意味します
メインスレッドを呼び出すか、呼び出して UI を更新しますsetState()
。
Android のスレッドとは異なり、
アイソレートはその名の通り、記憶を共有できない
(たとえば、静的フィールドの形式で)。
次の例は、単純な分離でデータを共有する方法を示しています。 UIを更新するメインスレッド。
Future<void> loadData() async {
ReceivePort receivePort = ReceivePort();
await Isolate.spawn(dataLoader, receivePort.sendPort);
// The 'echo' isolate sends its SendPort as the first message.
SendPort sendPort = await receivePort.first;
List msg = await sendReceive(
sendPort,
'https://jsonplaceholder.typicode.com/posts',
);
setState(() {
widgets = msg;
});
}
// The entry point for the isolate.
static Future<void> dataLoader(SendPort sendPort) async {
// Open the ReceivePort for incoming messages.
ReceivePort port = ReceivePort();
// Notify any other isolates what port this isolate listens to.
sendPort.send(port.sendPort);
await for (var msg in port) {
String data = msg[0];
SendPort replyTo = msg[1];
String dataURL = data;
http.Response response = await http.get(Uri.parse(dataURL));
// Lots of JSON to parse
replyTo.send(jsonDecode(response.body));
}
}
Future sendReceive(SendPort port, msg) {
ReceivePort response = ReceivePort();
port.send([msg, response.sendPort]);
return response.first;
}
ここ、dataLoader()
それはIsolate
独自の個別で実行される
実行スレッド。分離では、より多くの CPU を使用する実行が可能になります
処理 (大きな JSON の解析など)、
または、計算量の多い数学を実行する場合、
暗号化や信号処理など。
以下の完全な例を実行できます。
import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List widgets = [];
@override
void initState() {
super.initState();
loadData();
}
Widget getBody() {
bool showLoadingDialog = widgets.isEmpty;
if (showLoadingDialog) {
return getProgressDialog();
} else {
return getListView();
}
}
Widget getProgressDialog() {
return const Center(child: CircularProgressIndicator());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: getBody(),
);
}
ListView getListView() {
return ListView.builder(
itemCount: widgets.length,
itemBuilder: (context, position) {
return getRow(position);
},
);
}
Widget getRow(int i) {
return Padding(
padding: const EdgeInsets.all(10),
child: Text("Row ${widgets[i]["title"]}"),
);
}
Future<void> loadData() async {
ReceivePort receivePort = ReceivePort();
await Isolate.spawn(dataLoader, receivePort.sendPort);
// The 'echo' isolate sends its SendPort as the first message.
SendPort sendPort = await receivePort.first;
List msg = await sendReceive(
sendPort,
'https://jsonplaceholder.typicode.com/posts',
);
setState(() {
widgets = msg;
});
}
// The entry point for the isolate.
static Future<void> dataLoader(SendPort sendPort) async {
// Open the ReceivePort for incoming messages.
ReceivePort port = ReceivePort();
// Notify any other isolates what port this isolate listens to.
sendPort.send(port.sendPort);
await for (var msg in port) {
String data = msg[0];
SendPort replyTo = msg[1];
String dataURL = data;
http.Response response = await http.get(Uri.parse(dataURL));
// Lots of JSON to parse
replyTo.send(jsonDecode(response.body));
}
}
Future sendReceive(SendPort port, msg) {
ReceivePort response = ReceivePort();
port.send([msg, response.sendPort]);
return response.first;
}
}
Flutter の OkHttp に相当するものは何ですか?
Flutter でネットワーク呼び出しを行うのは、
人気http
パッケージ。
http パッケージには OkHttp にあるすべての機能が含まれているわけではありませんが、 通常実装するネットワーキングの多くを抽象化します。 ネットワーク通話を簡単に行うことができます。
追加するには、http
パッケージを依存関係として実行しますflutter pub add
:
$ flutter pub add http
ネットワーク通話を行うには、await
でasync
関数http.get()
:
import 'dart:developer' as developer;
import 'package:http/http.dart' as http;
Future<void> loadData() async {
var dataURL = Uri.parse('https://jsonplaceholder.typicode.com/posts');
http.Response response = await http.get(dataURL);
developer.log(response.body);
}
長時間実行されるタスクの進行状況を表示するにはどうすればよいですか?
Android では通常、ProgressBar
UI で表示しながら、
バックグラウンド スレッドで長時間実行されるタスクを実行する。
Flutter では、ProgressIndicator
ウィジェット。
レンダリングのタイミングを制御することで、プログラムで進行状況を表示します
ブール値フラグを介して。 Flutter に、実行前に状態を更新するように指示します。
長時間実行タスクが開始され、終了後に非表示になります。
次の例では、ビルド関数が 3 つの異なる関数に分割されています。
機能。もしもshowLoadingDialog
はtrue
(いつwidgets.isEmpty
)、
次にレンダリングしますProgressIndicator
。それ以外の場合は、レンダリングListView
ネットワーク呼び出しから返されたデータを使用します。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List widgets = [];
@override
void initState() {
super.initState();
loadData();
}
Widget getBody() {
bool showLoadingDialog = widgets.isEmpty;
if (showLoadingDialog) {
return getProgressDialog();
} else {
return getListView();
}
}
Widget getProgressDialog() {
return const Center(child: CircularProgressIndicator());
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: getBody(),
);
}
ListView getListView() {
return ListView.builder(
itemCount: widgets.length,
itemBuilder: (context, position) {
return getRow(position);
},
);
}
Widget getRow(int i) {
return Padding(
padding: const EdgeInsets.all(10),
child: Text("Row ${widgets[i]["title"]}"),
);
}
Future<void> loadData() async {
var dataURL = Uri.parse('https://jsonplaceholder.typicode.com/posts');
http.Response response = await http.get(dataURL);
setState(() {
widgets = jsonDecode(response.body);
});
}
}
プロジェクトの構造とリソース
解像度に依存する画像ファイルはどこに保存すればよいですか?
Android はリソースとアセットを別個のアイテムとして扱いますが、
Flutter アプリにはアセットのみがあります。生存するすべてのリソース
の中にres/drawable-*
Android 上のフォルダー、
Flutter のアセットフォルダーに配置されます。
Flutter は、iOS のような単純な密度ベースの形式に従います。
資産は次のとおりである可能性があります1.0x
、2.0x
、3.0x
、またはその他の乗数。
flutterにはありませんdp
論理ピクセルはありますが、
これは基本的にデバイスに依存しないピクセルと同じです。
flutterズdevicePixelRatio
比率を表します
単一の論理ピクセル内の物理ピクセルの数。
Android の密度バケットに相当するものは次のとおりです。
Android 密度修飾子 | flutterピクセル率 |
---|---|
ldpi |
0.75x |
mdpi |
1.0x |
hdpi |
1.5x |
xhdpi |
2.0x |
xxhdpi |
3.0x |
xxxhdpi |
4.0x |
アセットは任意のフォルダー (Flutter) にあります。
事前定義されたフォルダー構造はありません。
資産を(場所とともに)宣言します。
のpubspec.yaml
ファイルを開くと、Flutter がそれらを取得します。
ネイティブ アセット フォルダーに保存されているアセットは、
Android を使用してネイティブ側でアクセスするAssetManager
:
val flutterAssetStream = assetManager.open("flutter_assets/assets/my_flutter_asset.png")
Flutter はネイティブのリソースやアセットにアクセスできません。
という新しい画像アセットを追加するには、my_icon.png
Flutter プロジェクトに、
たとえば、フォルダーに保存する必要があると判断した場合、
勝手に呼ばれるimages
、ベース画像 (1.0x) を配置します。
の中にimages
フォルダー、およびサブフォルダー内の他のすべてのバリアント
適切な比率乗数を使用して呼び出されます。
images/my_icon.png // Base: 1.0x image
images/2.0x/my_icon.png // 2.0x image
images/3.0x/my_icon.png // 3.0x image
次に、これらのイメージをpubspec.yaml
ファイル:
assets:
- images/my_icon.jpeg
その後、次を使用して画像にアクセスできますAssetImage
:
AssetImage('images/my_icon.jpeg')
または直接Image
ウィジェット:
@override
Widget build(BuildContext context) {
return Image.asset('images/my_image.png');
}
文字列はどこに保存すればよいですか?ローカリゼーションはどのように処理すればよいですか?
Flutter には現在、文字列用の専用のリソースのようなシステムがありません。 現時点でのベスト プラクティスは、コピー テキストをクラス内に保持することです。 静的フィールドとそこからのアクセス。例えば:
class Strings {
static String welcomeMessage = 'Welcome To Flutter';
}
次に、コード内で次のように文字列にアクセスできます。
Text(Strings.welcomeMessage);
Flutter は Android でのアクセシビリティの基本的なサポートを備えています。 ただし、この機能は開発中のものです。
Flutter 開発者は、国際パッケージ国際化とローカリゼーションのために。
Gradle ファイルに相当するものは何ですか?依存関係を追加するにはどうすればよいですか?
Android では、Gradle ビルド スクリプトに追加することで依存関係を追加します。 Flutter は、Dart 独自のビルド システムと Pub パッケージ マネージャーを使用します。 このツールは、ネイティブ Android および iOS の構築を委任します。 ラッパー アプリをそれぞれのビルド システムに追加します。
Gradle ファイルは以下にありますが、android
フォルダー内の
Flutter プロジェクト。ネイティブを追加する場合にのみこれらを使用します。
プラットフォームごとの統合に必要な依存関係。
一般に、使用しますpubspec.yaml
宣言する
Flutter で使用する外部依存関係。
Flutter パッケージを見つけるのに適した場所は次のとおりです。パブ.dev。
アクティビティとフラグメント
Flutter のアクティビティとフラグメントに相当するものは何ですか?
Android では、Activity
ユーザーが実行できる単一の焦点を絞ったことを表します。
あFragment
動作またはユーザー インターフェイスの一部を表します。
フラグメントはコードをモジュール化し、洗練されたコードを構成する方法です。
より大きな画面向けのユーザー インターフェイスを提供し、アプリケーション UI の拡張に役立ちます。
Flutter では、これらの概念は両方とも以下の範疇に当てはまります。Widget
s.
アクティビティとフラグメントを構築するための UI について詳しくは、 コミュニティが投稿した Medium の記事を参照してください。Android 開発者向け Flutter: Flutter でアクティビティ UI を設計する方法。
で述べたように、インテントセクション、
Flutter の画面は次のように表されます。Widget
すべてがそうだから
Flutter のウィジェット。使うNavigator
異なる間を移動するRoute
さまざまな画面またはページを表す
あるいは、同じデータの異なる状態やレンダリングが考えられます。
Android アクティビティのライフサイクル イベントをリッスンするにはどうすればよいですか?
Android では、Activity
ライフサイクルを捉える
アクティビティ自体のメソッド、または登録ActivityLifecycleCallbacks
の上
のApplication
。 Flutter にはどちらの概念もありませんが、代わりに次のことができます。
にフックしてライフサイクル イベントをリッスンします。WidgetsBinding
観察者と
を聞いているdidChangeAppLifecycleState()
変更イベント。
監視可能なライフサイクル イベントは次のとおりです。
- e4029409-2530-41b7-9dc7-f78aecbba26— アプリケーションは依然として flutter エンジン上でホストされていますが、ホスト ビューからは切り離されています。
-
inactive
— アプリケーションは非アクティブ状態にあり、ユーザーを受信していません。 入力。 -
paused
— アプリケーションは現在ユーザーに表示されていません。 ユーザー入力に応答せず、バックグラウンドで実行されます。 これは以下と同等ですonPause()
アンドロイドで。 -
resumed
— アプリケーションが表示され、ユーザー入力に応答します。 これは以下と同等ですonPostResume()
アンドロイドで。
これらの状態の意味の詳細については、「AppLifecycleStatus
ドキュメンテーション。
お気づきかと思いますが、アクティビティのほんの一部だけが
ライフサイクル イベントが利用可能です。その間FlutterActivity
する
ほぼすべてのアクティビティ ライフサイクル イベントを内部的にキャプチャし、
それらを Flutter エンジンに送信します。ほとんどがシールドされています
あなたから離れて。 Flutter は、
あなたのためのエンジンであり、そうする必要がある理由はほとんどありません
ほとんどの場合、Flutter 側でアクティビティのライフサイクルを観察します。
ライフサイクルを観察して取得または解放する必要がある場合は、
ネイティブ リソースの場合、おそらくネイティブ側から実行する必要があります。
いずれにせよ。
以下は、ライフサイクルステータスを観察する方法の例です。 アクティビティを含む:
import 'package:flutter/widgets.dart';
class LifecycleWatcher extends StatefulWidget {
const LifecycleWatcher({super.key});
@override
State<LifecycleWatcher> createState() => _LifecycleWatcherState();
}
class _LifecycleWatcherState extends State<LifecycleWatcher>
with WidgetsBindingObserver {
AppLifecycleState? _lastLifecycleState;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() {
_lastLifecycleState = state;
});
}
@override
Widget build(BuildContext context) {
if (_lastLifecycleState == null) {
return const Text(
'This widget has not observed any lifecycle changes.',
textDirection: TextDirection.ltr,
);
}
return Text(
'The most recent lifecycle state this widget observed was: $_lastLifecycleState.',
textDirection: TextDirection.ltr,
);
}
}
void main() {
runApp(const Center(child: LifecycleWatcher()));
}
レイアウト
LinearLayout に相当するものは何ですか?
Android では、ウィジェットをレイアウトするために LinearLayout が使用されます 水平方向または垂直方向に直線的に。 Flutter では、行または列を使用します ウィジェットを使用して同じ結果を実現します。
2 つのコード サンプルが次の点を除いて同一であることに気付いた場合は、 「行」と「列」ウィジェット。子は同じなので、この機能は次のようになります。 時間の経過とともに変更できるリッチなレイアウトの開発に利用されます。 子供。
@override
Widget build(BuildContext context) {
return const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Row One'),
Text('Row Two'),
Text('Row Three'),
Text('Row Four'),
],
);
}
@override
Widget build(BuildContext context) {
return const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Column One'),
Text('Column Two'),
Text('Column Three'),
Text('Column Four'),
],
);
}
線形レイアウトの構築について詳しくは、 コミュニティが投稿した Medium 記事を参照してくださいAndroid 開発者向け Flutter: Flutter で LinearLayout を設計する方法。
RelativeLayout に相当するものは何ですか?
RelativeLayout は、ウィジェットを相互に相対的に配置します。の Flutter では、同じ結果を達成する方法がいくつかあります。
次の組み合わせを使用して、RelativeLayout の結果を実現できます。 列、行、およびスタックのウィジェット。ウィジェットのルールを指定できます 親に対して子がどのように配置されるかを指定するコンストラクター。
Flutter で RelativeLayout を構築する良い例として、 コリンの答えを参照してくださいスタックオーバーフロー。
ScrollView に相当するものは何ですか?
Android では、ScrollView を使用してウィジェットをレイアウトします。 デバイスの画面がコンテンツより小さい場合、スクロールします。
Flutter では、これを行う最も簡単な方法は ListView ウィジェットを使用することです。 これは Android のやりすぎのように思えるかもしれませんが、 しかし、Flutter では ListView ウィジェットは ScrollView と Android ListView の両方。
@override
Widget build(BuildContext context) {
return ListView(
children: const <Widget>[
Text('Row One'),
Text('Row Two'),
Text('Row Three'),
Text('Row Four'),
],
);
}
Flutter でランドスケープの遷移を処理するにはどうすればよいですか?
AndroidManifest.xml に以下が含まれている場合、FlutterView は構成変更を処理します。
android:configChanges="orientation|screenSize"
ジェスチャー検出とタッチイベント処理
Flutter のウィジェットに onClick リスナーを追加するにはどうすればよいですか?
Android では、呼び出して onClick をボタンなどのビューにアタッチできます。 メソッド「setOnClickListener」。
Flutter では、タッチ リスナーを追加する方法が 2 つあります。
- ウィジェットがイベント検出をサポートしている場合は、ウィジェットに関数を渡して処理します。
関数内で。たとえば、ElevatedButton には
onPressed
パラメータ:
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
developer.log('click');
},
child: const Text('Button'),
);
}
- ウィジェットがイベント検出をサポートしていない場合は、
GestureDetector のウィジェットを作成し、関数を
onTap
パラメータ。
class SampleTapApp extends StatelessWidget {
const SampleTapApp({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onTap: () {
developer.log('tap');
},
child: const FlutterLogo(
size: 200,
),
),
),
);
}
}
ウィジェット上で他のジェスチャを処理するにはどうすればよいですか?
GestureDetector を使用すると、次のような幅広いジェスチャを聞くことができます。
-
タップ
-
onTapDown
- タップの原因となるポインタが画面に接触した場合 特定の場所。 -
onTapUp
- タップをトリガーするポインタが接触を停止しました。 特定の場所の画面。 -
onTap
- タップが発生しました。 -
onTapCancel
- 以前にトリガーしたポインターonTapDown
しません タップの原因となります。
-
-
ダブルタップ
-
onDoubleTap
- ユーザーが画面の同じ場所を 2 回タップしました。 素早い連続。
-
-
長押し
-
onLongPress
- ポインタが画面に接触したままになっている 長期間同じ場所にいること。
-
-
垂直方向のドラッグ
-
onVerticalDragStart
- ポインタが画面に触れて、 垂直方向に動き始めるかもしれません。 -
onVerticalDragUpdate
- 画面に接触しているポインタ さらに垂直方向に移動しました。 -
onVerticalDragEnd
- 以前に接触していたポインタ 画面と垂直に移動すると画面と接触しなくなり、 画面との接触が停止すると、特定の速度で移動します。
-
-
水平方向のドラッグ
-
onHorizontalDragStart
- ポインタが画面に接触し、開始する可能性があります。 水平方向に移動します。 -
onHorizontalDragUpdate
- 画面に接触しているポインタ さらに水平方向に移動しました。 -
onHorizontalDragEnd
- 以前に接触していたポインタ 画面と水平方向の移動が接触しなくなりました。 画面が表示され、停止したときに特定の速度で移動していました 画面に接触しています。
-
次の例は、GestureDetector
ダブルタップで Flutter ロゴを回転させます。
class SampleApp extends StatefulWidget {
const SampleApp({super.key});
@override
State<SampleApp> createState() => _SampleAppState();
}
class _SampleAppState extends State<SampleApp>
with SingleTickerProviderStateMixin {
late AnimationController controller;
late CurvedAnimation curve;
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 2000),
);
curve = CurvedAnimation(
parent: controller,
curve: Curves.easeIn,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onDoubleTap: () {
if (controller.isCompleted) {
controller.reverse();
} else {
controller.forward();
}
},
child: RotationTransition(
turns: curve,
child: const FlutterLogo(
size: 200,
),
),
),
),
);
}
}
リストビューとアダプター
Flutter の ListView の代替となるものは何ですか?
Flutter の ListView に相当するのは、ListView です。
Android ListView では、アダプターを作成し、それを ListView。アダプターが返す内容を使用して各行をレンダリングします。しかし、あなたは 行を必ずリサイクルする必要があります。そうしないと、あらゆる種類のおかしなことになります 視覚的な不具合とメモリの問題。
Flutter の不変ウィジェット パターンにより、次のリストを渡します。 ウィジェットを ListView に追加すると、Flutter がそれを確認します。 スクロールが速くてスムーズです。
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: ListView(children: _getListData()),
);
}
List<Widget> _getListData() {
List<Widget> widgets = [];
for (int i = 0; i < 100; i++) {
widgets.add(Padding(
padding: const EdgeInsets.all(10),
child: Text('Row $i'),
));
}
return widgets;
}
}
どのリスト項目がクリックされたかを確認するにはどうすればよいですか?
Android では、ListView にどの項目がクリックされたかを調べるメソッドがあります。 「onItemClickListener」。 Flutter では、渡されたウィジェットによって提供されるタッチ処理を使用します。
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: ListView(children: _getListData()),
);
}
List<Widget> _getListData() {
List<Widget> widgets = [];
for (int i = 0; i < 100; i++) {
widgets.add(
GestureDetector(
onTap: () {
developer.log('row tapped');
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Text('Row $i'),
),
),
);
}
return widgets;
}
}
ListView を動的に更新するにはどうすればよいですか?
Android では、アダプターを更新して呼び出します。notifyDataSetChanged
。
Flutter で、ウィジェット内のウィジェットのリストを更新するとします。setState()
、
データが視覚的に変化していないことがすぐにわかります。
なぜなら、いつsetState()
Flutter レンダリング エンジンと呼ばれます
ウィジェット ツリーを見て、何か変更があったかどうかを確認します。それがあなたの手元に届いたら、ListView
を実行します。==
チェックして、その 2 つが一致していると判断します。ListView
も同じです。何も変更されていないため、更新する必要はありません。
を更新する簡単な方法については、ListView
、 新しいを作成しますList
の中にsetState()
をクリックして、古いリストから新しいリストにデータをコピーします。
このアプローチはシンプルですが、大規模なデータセットには推奨されません。
次の例に示すように。
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Widget> widgets = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 100; i++) {
widgets.add(getRow(i));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: ListView(children: widgets),
);
}
Widget getRow(int i) {
return GestureDetector(
onTap: () {
setState(() {
widgets = List.from(widgets);
widgets.add(getRow(widgets.length));
developer.log('row $i');
});
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Text('Row $i'),
),
);
}
}
リストを作成するための推奨される、効率的かつ効果的な方法では、ListView.Builder
。この方法は、動的なイベントがある場合に最適です。List
またはList
非常に大量のデータが含まれます。これは本質的には
Android の RecyclerView に相当し、自動的に
リスト要素をリサイクルします。
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List<Widget> widgets = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 100; i++) {
widgets.add(getRow(i));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: ListView.builder(
itemCount: widgets.length,
itemBuilder: (context, position) {
return getRow(position);
},
),
);
}
Widget getRow(int i) {
return GestureDetector(
onTap: () {
setState(() {
widgets.add(getRow(widgets.length));
developer.log('row $i');
});
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Text('Row $i'),
),
);
}
}
「ListView」を作成する代わりに、ListView.builder
これは 2 つの重要なパラメータを取ります。
リストの初期の長さ、およびItemBuilder
関数。
のItemBuilder
関数は次のようなものですgetView
Android アダプターで機能します。それは位置をとり、
そして、その位置にレンダリングしたい行を返します。
最後に、しかし最も重要なことですが、onTap()
関数
リストはもう再作成されませんが、代わりに.add
それには。
テキストの操作
テキスト ウィジェットにカスタム フォントを設定するにはどうすればよいですか?
Android SDK (Android O 以降) では、フォント リソース ファイルを作成し、 それを TextView の FontFamily パラメータに渡します。
Flutter では、フォント ファイルをフォルダーに配置し、pubspec.yaml
画像をインポートする方法と同様に、ファイルを作成します。
fonts:
- family: MyCustomFont
fonts:
- asset: fonts/MyCustomFont.ttf
- style: italic
次にフォントをText
ウィジェット:
テキスト ウィジェットのスタイルを設定するにはどうすればよいですか?
フォントに加えて、他のスタイル要素もカスタマイズできます。Text
ウィジェット。
のスタイルパラメータText
ウィジェットはTextStyle
できる限りオブジェクトを
次のような多くのパラメータをカスタマイズします。
- 色
- 装飾
- 装飾色
- 装飾スタイル
- フォントファミリー
- フォントサイズ
- フォントスタイル
- フォントの太さ
- ハッシュコード
- 身長
- 継承する
- 文字間隔
- テキストベースライン
- 単語間隔
フォーム入力
フォームの使用方法の詳細については、 見るテキストフィールドの値を取得する、 から flutterクックブック。
入力における「ヒント」に相当するものは何ですか?
Flutter では、次の方法で入力の「ヒント」またはプレースホルダー テキストを簡単に表示できます。 InputDecoration オブジェクトを装飾コンストラクター パラメーターに追加します。 テキストウィジェット。
Center(
child: TextField(
decoration: InputDecoration(hintText: 'This is a hint'),
),
)
検証エラーを表示するにはどうすればよいですか?
「ヒント」と同じように、InputDecoration オブジェクトを渡します。 Text ウィジェットの装飾コンストラクターに追加します。
ただし、最初からエラーを表示することは望ましくありません。
代わりに、ユーザーが無効なデータを入力した場合、
状態を更新し、新しい値を渡しますInputDecoration
物体。
import 'package:flutter/material.dart';
void main() {
runApp(const SampleApp());
}
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
const SampleAppPage({super.key});
@override
State<SampleAppPage> createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
String? _errorText;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sample App'),
),
body: Center(
child: TextField(
onSubmitted: (text) {
setState(() {
if (!isEmail(text)) {
_errorText = 'Error: This is not an email';
} else {
_errorText = null;
}
});
},
decoration: InputDecoration(
hintText: 'This is a hint',
errorText: _getErrorText(),
),
),
),
);
}
String? _getErrorText() {
return _errorText;
}
bool isEmail(String em) {
String emailRegexp =
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|'
r'(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|'
r'(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regExp = RegExp(emailRegexp);
return regExp.hasMatch(em);
}
}
flutterプラグイン
GPS センサーにアクセスするにはどうすればよいですか?
使用geolocator
コミュニティプラグイン。
カメラにアクセスするにはどうすればよいですか?
のimage_picker
プラグインが人気です
カメラにアクセスするため。
Facebook にログインするにはどうすればよいですか?
Facebook でログインするには、flutter_facebook_login
コミュニティプラグイン。
Firebase の機能を使用するにはどうすればよいですか?
Firebase のほとんどの機能は以下でカバーされています。ファーストパーティのプラグイン。 これらのプラグインはファーストパーティの統合です。 Flutter チームによって保守されています。
-
firebase_admob
Firebase AdMob 用 -
firebase_analytics
Firebase アナリティクス用 -
firebase_auth
Firebase認証の場合 -
firebase_database
Firebase RTDB 用 -
firebase_storage
Firebaseクラウドストレージ用 -
firebase_messaging
Firebase メッセージング (FCM) 用 -
flutter_firebase_ui
Firebase Auth 統合を迅速に行うため (Facebook、Google、Twitter、電子メール) -
cloud_firestore
Firebase クラウド Firestore 用
サードパーティの Firebase プラグインも次のサイトで見つけることができます。 pub.dev は、直接カバーされていない領域をカバーします。 ファーストパーティのプラグイン。
独自のカスタム ネイティブ統合を構築するにはどうすればよいですか?
Flutter が実行するプラットフォーム固有の機能がある場合 またはそのコミュニティのプラグインが見つからない、 次のように独自のものを構築できますパッケージとプラグインの開発ページ。
Flutter のプラグイン アーキテクチャは、一言で言えば、 Android: メッセージを送信し、受信者に結果を処理させて出力させます。 あなたに戻って。この場合、受信側はネイティブ側で実行されるコードです。 Android または iOS で。
Flutter アプリケーションで NDK を使用するにはどうすればよいですか?
現在の Android アプリケーションで NDK を使用していて、Flutter が必要な場合 アプリケーションがネイティブ ライブラリを利用できるようにするには、 カスタムプラグインを構築します。
カスタム プラグインはまず Android アプリと通信し、そこでnative
JNI を介して機能します。返答の準備ができたら、
Flutter にメッセージを送り返し、結果をレンダリングします。
Flutter から直接ネイティブ コードを呼び出すことは現在サポートされていません。
テーマ
アプリのテーマを設定するにはどうすればよいですか?
Flutter には、すぐに使えるマテリアルの美しい実装が付属しています。 デザイン: 多くのスタイルやテーマのニーズに対応します。 通常はそうします。 XML でテーマを宣言して割り当てる Android とは異なります。 AndroidManifest.xml を使用してアプリケーションに、Flutter でテーマを宣言します 最上位のウィジェット内。
アプリでマテリアル コンポーネントを最大限に活用するには、トップを宣言できます。
レベルウィジェットMaterialApp
アプリケーションへのエントリ ポイントとして。マテリアルアプリ
一般的に使用されるいくつかのウィジェットをラップする便利なウィジェットです。
マテリアル デザインを実装するアプリケーションに必要です。
これは、マテリアル固有の機能を追加することにより、WidgetsApp に基づいて構築されます。
を使用することもできますWidgetsApp
アプリのウィジェットとして使用すると、次のような機能が提供されます。
同じ機能ですが、それほど豊富ではありませんMaterialApp
。
子コンポーネントの色とスタイルをカスタマイズするには、ThemeData
に反対するMaterialApp
ウィジェット。たとえば、以下のコードでは、
プライマリ スウォッチは青に設定され、テキスト選択の色は赤に設定されます。
import 'package:flutter/material.dart';
class SampleApp extends StatelessWidget {
const SampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
textSelectionTheme:
const TextSelectionThemeData(selectionColor: Colors.red),
),
home: const SampleAppPage(),
);
}
}
データベースとローカルストレージ
共有設定にアクセスするにはどうすればよいですか?
Android では、次を使用してキーと値のペアの小さなコレクションを保存できます。 SharedPreferences API。
Flutter では、次のコマンドを使用してこの機能にアクセスします。Shared_Preferences プラグイン。 このプラグインは両方の機能をラップします。 共有設定と NSUserDefaults (iOS に相当)。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
runApp(
const MaterialApp(
home: Scaffold(
body: Center(
child: ElevatedButton(
onPressed: _incrementCounter,
child: Text('Increment Counter'),
),
),
),
),
);
}
Future<void> _incrementCounter() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
int counter = (prefs.getInt('counter') ?? 0) + 1;
await prefs.setInt('counter', counter);
}
Flutter で SQLite にアクセスするにはどうすればよいですか?
Android では、SQLite を使用してクエリ可能な構造化データを保存します。 SQLを使用して。
Flutter では、次のコマンドを使用してこの機能にアクセスします。SQフライトプラグイン。
デバッグ
Flutter でアプリをデバッグするにはどのようなツールを使用できますか?
使用開発ツールFlutter または Dart アプリをデバッグするためのスイート。
DevTools には、プロファイリング、ヒープの検査、 ウィジェット ツリーの検査、診断のログ記録、デバッグ、 実行されたコード行の監視、メモリ リークとメモリのデバッグ 断片化。詳細については、「開発ツールドキュメンテーション。
通知
プッシュ通知を設定するにはどうすればよいですか?
Android では、Firebase Cloud Messaging を使用してプッシュを設定します アプリの通知。
Flutter では、次のコマンドを使用してこの機能にアクセスします。Firebaseメッセージングプラグイン。
Firebase Cloud Messaging API の使用方法の詳細については、
を参照してくださいfirebase_messaging
プラグインのドキュメント。